package com.physics.mps.module.abaqus;

import com.physics.mps.entity.vo.*;
import com.physics.mps.module.util.PyUtils;
import com.physics.mps.entity.vo.AbaqusBoundaryVo;
import com.physics.mps.entity.vo.AbaqusComputeParam;
import com.physics.mps.entity.vo.AbaqusRandomVibrationParam;
import com.physics.mps.entity.vo.AbaqusRandomVibrationStepVo;

import java.util.List;

/**
 * Abaqus计算模块：频率响应分析
 */
public class AbaqusHarmonicResponseHandler extends AbstractAbaqusComputeHandler {


    // ~ Variable & Constant
    // ========================================================================================================
    /**
     * 频率响应分析步参数(注：参数类型与随机振动分析步参数相同)
     */
    private AbaqusRandomVibrationStepVo randomVibrationStepVo;

    /**
     * 边界条件参数
     */
    private List<AbaqusBoundaryVo> boundaryVos;

    public AbaqusHarmonicResponseHandler setAbaqusComputeParam(AbaqusComputeParam randomVibrationParam) {
        this.abaqusComputeParam = randomVibrationParam;

        if (randomVibrationParam instanceof AbaqusRandomVibrationParam) {
            AbaqusRandomVibrationParam specificParam = (AbaqusRandomVibrationParam) randomVibrationParam;

            this.parts = specificParam.getParts();

            this.partNames = specificParam.getPartNames();

            this.meshVo = specificParam.getMeshVo();

            this.jobVo = specificParam.getJobVo();

            this.jobVo.setVariableLabel("S");

            this.jobVo.setOutputPosition("INTEGRATION_POINT");

            this.jobVo.setRefinement("(INVARIANT,'Mises')");

            this.randomVibrationStepVo = specificParam.getRandomVibrationStepVo();

            this.boundaryVos = specificParam.getBoundaryVos();

            super.tieVos = specificParam.getTieVos();

            this.setComputeParam = true;
        }

        return this;
    }

    // ~ Public method
    // ========================================================================================================


    // ~ Override method
    // ========================================================================================================

    @Override
    public void createStepAndFieldImpl(StringBuilder builder) {
        //5.创建分析步
        builder.append(this.createStep());

        //6.输出结果设置
        builder.append(this.createOutputCommand());

        //7.载荷设置

        //7.1 边界条件设置
        builder.append(this.createBoundaryCommand());

        //7.2 定义随机振动激励
        builder.append(this.createPsdDefinition());
    }

    @Override
    public void createStepImpl(StringBuilder builder) {
        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".FrequencyStep(name='Step-1', previous='Initial'")
                .append(", limitSavedEigenvectorRegion=None")
                .append(", numEigen=")
                .append(this.randomVibrationStepVo.getNumEigen()).append(")")
                .append(PyUtils.WRAP);

        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".SteadyStateModalStep(name='Step-2', previous='Step-1'")
                .append(", frequencyRange=")
                .append(this.randomVibrationStepVo.getFreq())
                .append(", directDamping=")
                .append(this.randomVibrationStepVo.getDirectDamping()).append(")")
                .append(PyUtils.WRAP);
    }

    @Override
    public void createBoundaryCommandImpl(StringBuilder builder) {
        builder.append("a = ")
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".rootAssembly")
                .append(PyUtils.WRAP);
        int i = 1;
        for (AbaqusBoundaryVo boundaryVo : boundaryVos) {
            builder
                    .append("f1 = a.instances['" + boundaryVo.getPartName() + "'].faces")
                    .append(PyUtils.WRAP);

            builder
                    .append("faces1 = f1.findAt(")
                    .append(PyUtils.coordinateConvertToString(boundaryVo.getCoordinate())).append(")")
                    .append(PyUtils.WRAP)
                    .append("region =a.Set(faces=faces1,name='Set-").append(i).append("')")
                    .append(PyUtils.WRAP);

            builder
                    .append(this.createMdbModelsCommand("Model-1"))
                    .append(".EncastreBC(name='BC-").append(i).append("', createStepName='Step-1', region=region, localCsys=None)")
                    .append(PyUtils.WRAP);
            i++;
        }
    }

    @Override
    public void createOutputCommandImpl(StringBuilder builder) {

    }

    @Override
    public void createElemTypeCommandImpl(StringBuilder builder) {
        builder.append("elemType1 = mesh.ElemType(elemCode=C3D20R, elemLibrary=STANDARD)").append(PyUtils.WRAP);
        builder.append("elemType2 = mesh.ElemType(elemCode=C3D15, elemLibrary=STANDARD)").append(PyUtils.WRAP);
        builder.append("elemType3 = mesh.ElemType(elemCode=C3D10, elemLibrary=STANDARD, secondOrderAccuracy=OFF, distortionControl=DEFAULT)").append(PyUtils.WRAP);
    }

    @Override
    public void createExportCommandImpl(StringBuilder builder) {
        builder.append("def loopAndCompare(instance_name):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("field_variable = harmonicFrame.fieldOutputs['E'].getSubset(region=instance[instance_name])").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("fieldValues = field_variable.values").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("max_val = field_variable.values[0].mises").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("for v in fieldValues:").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("if (v.mises > max_val):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(3)).append("max_val = v.mises").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("return max_val").append(PyUtils.WRAP);

        builder.append("from odbAccess import openOdb").append(PyUtils.WRAP);
        builder.append("from textRepr import *").append(PyUtils.WRAP);
        builder.append("my_odb = openOdb(r\"").append(this.workDir).append("\\\\").append(jobVo.getJobName()).append(".odb\")").append(PyUtils.WRAP);
        builder.append("len1 = ").append(partNames.size()).append(PyUtils.WRAP);
        builder.append("instance = my_odb.rootAssembly.instances").append(PyUtils.WRAP);
        builder.append("file = open('").append(this.workDir).append("\\\\PNG\\\\").append(this.jobVo.getJobName()).append(".txt', 'w')").append(PyUtils.WRAP);

        builder.append("len_frames=len(my_odb.steps['Step-2'].frames)").append(PyUtils.WRAP);
        builder.append("for i in range(1,len_frames):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("harmonicFrame = my_odb.steps['Step-2'].frames[i]").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("instance_name = 'COMPOUND'").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("max_val = loopAndCompare(instance_name)").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("file.write(instance_name + ':' + str(i) + ':' + str(max_val) + '\\n')").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("for j in range(1, len1):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("instance_name = 'COMPOUND-' + j").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("max_val = loopAndCompare(instance_name)").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("file.write(instance_name + ':' + str(i) + ':' + str(max_val) + '\\n')").append(PyUtils.WRAP);

        builder.append("file.close()").append(PyUtils.WRAP);
    }

    // ~ Private method
    // ========================================================================================================
    public String createOutputCommand() {
        StringBuilder builder = new StringBuilder();
        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".fieldOutputRequests['F-Output-1']")
                .append(".setValues(variables=('S', 'U'))")
                .append(PyUtils.WRAP);

        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".FieldOutputRequest(name='F-Output-2', createStepName='Step-2', variables=('S', 'E', 'U', 'V', 'A', 'RF'))")
                .append(PyUtils.WRAP);

        return builder.toString();
    }

    private String createPsdDefinition() {
        StringBuilder builder = new StringBuilder();

        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".TabularAmplitude(name='Amp-1'")
                .append(", timeSpan=STEP")
                .append(", smooth=SOLVER_DEFAULT")
                .append(", data=").append(randomVibrationStepVo.getData()).append(')')
                .append(PyUtils.WRAP);

        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".AccelerationBaseMotionBC(name='BC-2'")
                .append(", createStepName='Step-2'")
                .append(", amplitude='Amp-1'")
                .append(", dof=").append(randomVibrationStepVo.getDof())
                .append(", amplitudeScaleFactor=").append(randomVibrationStepVo.getReferenceGravityAcceleration())
                .append(')')
                .append(PyUtils.WRAP);

        return builder.toString();
    }

    // ~ Autowired
    // ========================================================================================================


}